<template>
  <div class="chat">
    <div>
      <chat-panel
        ref="chatPanelRef"
        :messages="messages"
        :generating="generating"
        :sd-service-available="sdServiceAvailable"
        @send="handleSend"
        @clear="clearMessages"
        @update:messages="messages = $event"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, nextTick, onMounted } from 'vue'
import ChatPanel from '@/components/ChatPanel.vue'
import { chatApi, type Message } from '@/services/chat'
import { ElMessage, ElLoading } from 'element-plus'

const messages = ref<Message[]>([])
const generating = ref(false)
const sdServiceAvailable = ref(false)
const chatPanelRef = ref<InstanceType<typeof ChatPanel> | null>(null)

const scrollToBottom = async () => {
  await nextTick()
  const messagesContainer = chatPanelRef.value?.$el.querySelector('.messages')
  if (messagesContainer) {
    messagesContainer.scrollTop = messagesContainer.scrollHeight
  }
}

// 在组件挂载时添加自动滚动
onMounted(async () => {
  try {
    // 加载历史消息
    const response = await chatApi.getHistory()
    if (response.data?.success && response.data.messages) {
      messages.value = response.data.messages
    }
  } catch (error) {
    console.error('加载历史记录失败:', error)
  }
  await scrollToBottom()
})

const handleSend = async (params: { text: string; model: string }) => {
  if (!params.text.trim()) return

  generating.value = true
  // 先添加用户消息
  messages.value.push({
    type: 'text',
    content: params.text,
    isUser: true,
    isExpanded: false
  })

  // 创建一个新的消息对象用于更新
  const assistantMessage = {
    type: 'text' as const,
    content: '',
    isUser: false,
    isExpanded: true
  }
  messages.value.push(assistantMessage)
  await scrollToBottom()

  // 尝试使用流式响应，如果失败则回退到非流式响应
  let useStreamMode = true
  let retryCount = 0
  const maxRetries = 1 // 最多重试一次

  while (retryCount <= maxRetries) {
    try {
      if (useStreamMode) {
        // 流式响应模式
        const response = await fetch('/api/chat', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            message: params.text,
            model: params.model,
            stream: true
          })
        })

        if (!response.ok) {
          const errorText = await response.text()
          console.error(`请求失败 (${response.status}): ${errorText}`)
          throw new Error(`请求失败 (${response.status}): ${errorText}`)
        }

        if (!response.body) {
          throw new Error('响应体为空')
        }

        // 读取流数据
        const reader = response.body.getReader()
        const decoder = new TextDecoder()

        let buffer = '' // 用于存储未完整解析的流数据
        while (true) {
          const { done, value } = await reader.read()
          if (done) break

          buffer += decoder.decode(value, { stream: true })

          // 拆分 SSE 数据
          const parts = buffer.split('\n\n')

          for (let i = 0; i < parts.length - 1; i++) {
            const line = parts[i].trim()
            if (line.startsWith('data: ')) {
              try {
                const jsonStr = line.substring(6).trim() // 去掉 `data: ` 前缀
                const jsonData = JSON.parse(jsonStr) // 解析 JSON
                if (jsonData.error) {
                  ElMessage.error(jsonData.error)
                  throw new Error(jsonData.error)
                }

                if (!jsonData.done) {
                  assistantMessage.content += jsonData.content
                  await scrollToBottom()
                } else {
                  generating.value = false
                  break
                }
              } catch (e) {
                console.error('解析响应数据失败:', e)
                throw e
              }
            }
          }
          // 只保留最后一个未完整的部分
          buffer = parts[parts.length - 1]
        }

        // 如果成功完成，跳出重试循环
        break
      } else {
        // 非流式响应模式
        const loadingInstance = ElLoading.service({
          lock: true,
          text: '正在生成回复...',
          background: 'rgba(0, 0, 0, 0.7)'
        })

        try {
          const response = await fetch('/api/chat', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              message: encodeURIComponent(params.text),
              model: encodeURIComponent(params.model),
              stream: false
            })
          })

          if (!response.ok) {
            const errorText = await response.text()
            throw new Error(`请求失败 (${response.status}): ${errorText}`)
          }

          const result = await response.json()

          if (result.error) {
            ElMessage.error(result.error)
            throw new Error(result.error)
          }

          // 更新消息内容
          assistantMessage.content = result.content || ''
          await scrollToBottom()

          // 如果成功完成，跳出重试循环
          break
        } finally {
          loadingInstance.close()
        }
      }
    } catch (error) {
      console.error(`发送消息失败 (${useStreamMode ? '流式' : '非流式'}模式):`, error)

      // 如果是流式模式失败，尝试切换到非流式模式
      if (useStreamMode && retryCount < maxRetries) {
        useStreamMode = false
        retryCount++
        ElMessage.warning('流式响应失败，正在尝试非流式模式...')
        continue // 重试，使用非流式模式
      }

      // 所有尝试都失败，显示错误消息
      ElMessage.error(`发送消息失败: ${error instanceof Error ? error.message : '未知错误'}`)
      assistantMessage.content = '消息发送失败，请稍后重试。'
      break
    } finally {
      generating.value = false
      await scrollToBottom()
    }
  }
}

const clearMessages = () => {
  messages.value = []
}
</script>

<style scoped>
/* .container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
} */

.chat-card {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.chat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 1rem;
  flex-shrink: 0;
}

.chat {
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  min-height: 0;
}
</style>
